/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cqcis.uip.base.framework.base.impl;

import java.util.concurrent.ThreadPoolExecutor;

import org.codehaus.xfire.XFire;
import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.server.http.XFireHttpServer;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import org.codehaus.xfire.service.invoker.BeanInvoker;

import com.cqcis.uip.base.framework.UIPServiceException;
import com.cqcis.uip.base.framework.UIPTaskException;
import com.cqcis.uip.base.framework.base.adaptor.AbstractRegisteredService;
import com.cqcis.uip.base.framework.common.Role;
import com.cqcis.uip.base.framework.common.Task;
import com.cqcis.uip.base.framework.core.RegisteredServiceContext;
import com.cqcis.uip.base.framework.core.ServiceRole;
import com.cqcis.uip.base.framework.core.TaskResultProcessor;
import com.cqcis.uip.base.framework.handlers.CommonService;
import com.cqcis.uip.base.framework.utils.AnnotationUtil;
import com.cqcis.uip.base.framework.utils.DynamicAsyncMethodProxyUtil;
import com.cqcis.uip.base.framework.utils.LogServiceThreadPoolExecutor;

/**
 * WebService服务发布
 * 
 * @author huangmy
 * @date   2008-9-6
 */
public class DefaultWebServicePublisher extends AbstractRegisteredService {
	private static final long serialVersionUID = 1L;
	private ThreadPoolExecutor proxyExecutor; // proxy
	private XFireHttpServer server; // SERVER	
	private Object webServiceTarget;// implemention target
	private int port; // 端口
	private DefaultCommoner commoner;
	
	@Override
	public void start(RegisteredServiceContext serviceContext) throws Exception {
		if (this.webServiceTarget == null) {
			throw new UIPServiceException("webServiceTarget Can't be null.");
		}
		
		super.start(serviceContext);
		
		this.proxyExecutor = LogServiceThreadPoolExecutor.getLogExecutor(0, 0, 0, 
				serviceContext, "DynamicAsyncMethodProxy-" + serviceContext.getRegisteredService().getName());
		
		// 获取需要发布的WebService服务接口
		Class<?> serviceClazz = getPublishInterfaceForWSDL(this.webServiceTarget);
		
		if (this.webServiceTarget instanceof com.cqcis.uip.base.framework.core.Service) {
			((com.cqcis.uip.base.framework.core.Service) this.webServiceTarget).start(serviceContext);
		}
		
		Object serviceProxyTarget = DynamicAsyncMethodProxyUtil.create(this.webServiceTarget, serviceClazz, this.proxyExecutor);
		
		ObjectServiceFactory serviceFactory = new ObjectServiceFactory();				
		Service service = serviceFactory.create(serviceClazz);
	    service.setInvoker(new BeanInvoker(serviceProxyTarget));

		XFire xfire = XFireFactory.newInstance().getXFire();
		xfire.getServiceRegistry().register(service);
		// Start the HTTP server
		this.server = new XFireHttpServer(xfire);
		this.server.setPort(this.port);
		 
		this.server.start(); // START
		
		if (this.webServiceTarget instanceof CommonService) {
    		CommonService serviceComm = (CommonService)this.webServiceTarget;
    		this.commoner = new DefaultCommoner();
    		this.commoner.setBundleContext(this.bundleContext);
    		this.commoner.registerLogConfiguration(this.getLogConfiguration());
    		this.commoner.setCommonService(serviceComm);
    		this.commoner.setEndpointExpression(this.endpointExpression);
    		this.commoner.setInterfaceId(this.interfaceId);
    		this.commoner.setInterfaceName(this.interfaceName);
    		this.commoner.setIntervalTime(this.intervalTime);
    		this.commoner.setLogDir(this.logDir);
    		this.commoner.setLogLevel(this.logLevel);
    		this.commoner.setStreamLogOutputService(this.streamLogOutputService);
    		this.commoner.setThreadNumberExtendTaskResultProcessor(this.threadNumberExtendTaskResultProcessor);
    		this.commoner.setThreadNumberSchedule(this.threadNumberTaskDispatcher);
    		this.commoner.setThreadNumberTaskDispatcher(this.threadNumberTaskDispatcher);
    		this.commoner.setToEndpointExpression(this.toEndpoint.getExpression());
    		this.commoner.setThreadNumberTaskResultDispatcher(this.threadNumberTaskResultDispatcher);
    		this.commoner.setWaitTaskMax(this.waitTaskMax);
    		
    		this.commoner.start(serviceContext);
    	}
	}
	
	@Override
	public void stop(RegisteredServiceContext serviceContext) throws Exception {
		if (this.webServiceTarget instanceof com.cqcis.uip.base.framework.core.Service) {
			((com.cqcis.uip.base.framework.core.Service) this.webServiceTarget).stop(serviceContext);
		}
		
		if (this.commoner != null) {
    		this.commoner.stop(serviceContext);
    	}
		
		if (this.server != null) {
			this.server.stop();
		}
		
		if (this.proxyExecutor != null) {
			this.proxyExecutor.shutdown();
		}
		
		super.stop(serviceContext);
	}

	@Override
	protected boolean doSchedule() {		
		return doScheduleSync(getTaskQueue().poll());
	}
	
	@Override
    protected boolean doScheduleSync(Task task) {
		if (this.commoner == null) {
			throw new UIPServiceException("the service maybe not implements CommonService.");
		}
    	try {
			return this.commoner.scheduleSync(task);
		} catch (Exception e) {
			throw new UIPTaskException(e);
		}
    }
	
	@Override
	public boolean processResult(final Task result) {		
		if (this.webServiceTarget instanceof TaskResultProcessor) {
			getExtendProcessResultThreadPoolExecutor().execute(new Runnable() {
				public void run() {		
					try {
					    ((TaskResultProcessor)webServiceTarget).processResult(result);
					} finally {
						afterProcessResult(result);
					}
				}
			});
		} else {
			afterProcessResult(result);
		}
				
		return true;
	}
	
	/**
	 * 获取需要发布的接口
	 * 
	 * @param target
	 * @return
	 */
	private static Class<?> getPublishInterfaceForWSDL(Object target) {
		Class<?> clazz = AnnotationUtil.findDeepAnnotationInterfaceForClass(target.getClass(), ServiceRole.class);
		if (clazz == null) {
			throw new UIPServiceException("Can't find interface for publishing, " +
					"maybe you have not set @ServiceRole(Role.WEBSERVICE_PUBLISHER) Annotation for Interface.");
		}
		return clazz;
	}
    	
	public Role getRole() {		
		return Role.WEBSERVICE_PUBLISHER;
	}

	@ServiceRole(Role.WEBSERVICE_PUBLISHER)
	public void setWebServiceTarget(Object webServiceTarget) {
		this.webServiceTarget = webServiceTarget;
	}

	/**
	 * 端口
	 * 
	 * @param port
	 */
	public void setPort(int port) {
		this.port = port;
	}
}
